<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <a href="https://v2.cn.vuejs.org/v2/api/#v-model">vue2 API网址：</a>
    </div>

    <div id="app">
        <p v-text="age"></p>
      <input type="text" v-model="age" />
      <p v-text="name"></p>
      <input type="text" v-model="name" />
    </div>
  </body>

  <!--  <script>
    // 响应式实现的方法
    const defineReactive = (data, key, value, setCallBack) => {
      Object.defineProperty(data, key, {
        get() {
          return value;
        },
        set(newValue) {
          if (newValue === value) return;
          value = newValue;
          if (setCallBack) setCallBack(newValue);
        },
      });
    };

    let data = {
      name: "名字xx",
      age: "年龄xx",
    };
    // 把data中的属性变成响应式的
    Object.keys(data).forEach((key) => {
      defineReactive(data, key, data[key], () => {
        // 设置成功后，执行的操作
        compile();
      });
    });

    // 通过标识查找把数据放到对应的dom上显示出来
    const compile = () => {
      let app = document.getElementById("app");
      const childNodes = app.childNodes;
      childNodes.forEach((node) => {
        if (node.nodeType === 1) {
          const attrs = node.attributes;

          Array.from(attrs).forEach((attr) => {
            const nodeName = attr.nodeName;
            const nodeValue = attr.nodeValue;

            // 实现v-text
            if (nodeName === "v-text") {
              node.innerText = data[nodeValue];
            }

            // 实现v-model
            if (nodeName === "v-model") {
              node.value = data[nodeValue];

              node.addEventListener("input", (e) => {
                let newValue = e.target.value;
                data[nodeValue] = newValue;
              });
            }
          });
        }
      });
    };

    compile();

    // 控制台修改data.xx的参数
  </script> -->

  <script>
    // 引入发布订阅模式
    const Dep = {
      map: {},
      // 收集事件的方法
      collect(eventName, fn) {
        if (!this.map[eventName]) {
          this.map[eventName] = [];
        }
        this.map[eventName].push(fn);
      },
      // 触发事件的方法
      trigger(eventName) {
        this.map[eventName].forEach((fn) => fn());
      },
    };

    // 响应式实现的方法
    const defineReactive = (data, key, value, setCallBack) => {
      Object.defineProperty(data, key, {
        get() {
          return value;
        },
        set(newValue) {
          if (newValue === value) return;
          value = newValue;
          if (setCallBack) setCallBack(newValue);
        },
      });
    };

    let data = {
      name: "名字xx",
      age: "年龄xx",
    };

    // 把data中的属性变成响应式的
    Object.keys(data).forEach((key) => {
      defineReactive(data, key, data[key], () => {
        // 设置成功后，执行的操作
        // compile();
        Dep.trigger(key);
      });
    });

    // 通过标识查找把数据放到对应的dom上显示出来
    const compile = () => {
      let app = document.getElementById("app");
      const childNodes = app.childNodes;
      childNodes.forEach((node) => {
        if (node.nodeType === 1) {
          const attrs = node.attributes;

          Array.from(attrs).forEach((attr) => {
            const nodeName = attr.nodeName;
            const nodeValue = attr.nodeValue;

            // 实现v-text
            if (nodeName === "v-text") {
              node.innerText = data[nodeValue];

              // 收集更新函数
              Dep.collect(nodeValue, () => {
                console.log(`当前您修改了属性${nodeValue}`);
                node.innerText = data[nodeValue];
              });
            }

            // 实现v-model
            if (nodeName === "v-model") {
              node.value = data[nodeValue];

              // 收集更新函数
              Dep.collect(nodeValue, () => {
                node.value = data[nodeValue];
              });

              node.addEventListener("input", (e) => {
                let newValue = e.target.value;
                data[nodeValue] = newValue;
              });
            }
          });
        }
      });
    };

    compile();
  </script>
</html>
